﻿using System;
using System.Linq;
using System.Runtime.CompilerServices;
using RayDen.Library.Core.Primitives;

namespace RayDen.Library.Components.Volume
{
    public class AbstractField<TData>
    {
        protected TData[] data;
        protected int width, height, depth;

        public virtual TData this[float x, float y, float z]
        {
            get
            {
                return data[arrayIndexFromCoordinate((int)Math.Round(x), (int)Math.Round(y), (int)Math.Round(z))];
            }
        }

        public virtual TData this[int x, int y, int z]
        {
            get
            {
                return data[arrayIndexFromCoordinate(x, y, z)];
            }
        }

        public TData this[Point p]
        {
            get
            {
                return this[p.x, p.y, p.z];
            }
        }

        public int Width
        {
            get { return width; }
        }

        public int Height
        {
            get { return height; }
        }

        public int Depth
        {
            get { return depth; }
        }

        public AbstractField(int w, int h, int d)
        {
            this.width = w;
            this.height = h;
            this.depth = d;
            data = new TData[w*h*d];
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public TData GetData(int x, int y, int z)
        {
            return data[x + y*width + z*width*height];
        }

        public void Fill(TData dataItem)
        {
            data = Enumerable.Repeat(dataItem, width*height*depth).ToArray();
        }

        public void Fill(TData[] dataItems)
        {
            if (dataItems.Length < data.Length)
            {
                throw new ArgumentException("Invalid data length", "dataItems");
            }

            for (int k = 0; k < depth; ++k) {
                 for (int j = 0; j < height; ++j) {
                     for (int i = 0; i < width; ++i)
                         {
                             data[arrayIndexFromCoordinate(i, j, k)] = dataItems[arrayIndexFromCoordinate(i, j, k)];
                         }
                     }
                }
        }


        public virtual void Clear()
        {
            Array.Clear(data, 0, data.Length);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected int arrayIndexFromCoordinate(int i, int j, int k)
        {
            return i + j*width + k*width*height;
        }


    }
}